#ifndef GAME_RENDER_GROUP_H
#define GAME_RENDER_GROUP_H
#include "game_math.h"
#include "game.h"
#include "game_sort.h"

/*
1) 渲染器外部的所有地方，Y 始终向上，X 向右。
2) 所有位图，包括渲染目标，都假定为自底向上（即屏幕上显示时，第一行指向最底部的行）。
3) 除非另有说明，所有传递给渲染器的输入都是世界坐标（“米”），而不是像素值，任何像素值会明确标明。
4) Z 是一个特殊的坐标，因为它被分割成离散的切片，渲染器实际上能够理解这些切片。
*/

struct render_basis {
    //
    v3 P;
};

enum render_group_entry_type {
    RenderGroupEntryType_render_entry_bitmap,
    RenderGroupEntryType_render_entry_rectangle,
    RenderGroupEntryType_render_entry_coordinate_system,
    RenderGroupEntryType_render_entry_saturation,
    RenderGroupEntryType_render_entry_cliprect,
    RenderGroupEntryType_render_entry_blend_render_target,
};

// 结构体表示一个实体的可见部分
struct render_group_entry_header {
    render_group_entry_type Type;
    uint16 ClipRectIndex;
#if GAME_SLOW
    uint32 DebugTag;
#endif
};

struct render_entry_cliprect {
    render_entry_cliprect *Next;
    rectangle2i Rect;
    uint32 RenderTargetIndex;
};

struct render_entry_clear {
    v4 PremulColor;
};

// 定义渲染条目结构体，用于表示饱和度调整
struct render_entry_saturation {
    //
    real32 Level;  // 饱和度调整值，通常在0.0到1.0之间，控制图像的饱和度
};

struct render_entry_coordinate_system {
    //
    v2 Origin;
    v2 XAxis;
    v2 YAxis;
    v4 Color;
    loaded_bitmap *Texture;
    loaded_bitmap *NormalMap;

    real32 PixelIsToMeters;
    // 定义环境贴图指针，用于存储不同方向的环境贴图
    environment_map *Top;     // 存储顶部环境贴图
    environment_map *Middle;  // 存储中间部分环境贴图
    environment_map *Bottom;  // 存储底部环境贴图
};

struct render_entry_bitmap {
    loaded_bitmap *Bitmap;  // 指向实体可见部分的位图资源
    bitmap_id ID;
    v2 P;
    // 颜色的四个分量：红色、绿色、蓝色、透明度（alpha）
    v4 PremulColor;
    v2 XAxis;
    v2 YAxis;
};

struct render_entry_rectangle {
    v2 P;
    // 颜色的四个分量：红色、绿色、蓝色、透明度（alpha）
    v4 PremulColor;
    v2 Dim;  // v2 结构体存储尺寸的宽度和高度
};

struct render_entry_blend_render_target {
    uint32 SourceTargetIndex;
    real32 Alpha;
};

struct object_transform {
    bool32 Upright;
    v3 OffsetP;
    real32 Scale;
    manual_sort_key ManualSort;
    int32 ChunkZ;
    v4 tColor;
    v4 Color;
};

struct camera_transform {
    bool32 Orthographic;
    real32 MetersToPixels;
    v2 ScreenCenter;
    real32 FocalLength;
    real32 DistanceAboveTarget;

    rectangle2 ClipRect;
};

struct render_group_transform {
    bool32 Orthographic;
    // 注意：这将把显示器上的米数转换为显示器上的像素数
    real32 MetersToPixels;

    // 计算焦距和相机离目标的距离
    real32 FocalLength;
    // 焦距（单位：像素）
    real32 DistanceAboveTarget;
    // 相机到目标的垂直距离（单位：像素）
    v2 ScreenCenter;

    bool32 Upright;
    v3 OffsetP;
    real32 Scale;
};

// 结构体表示多个实体可见部分的集合
struct render_group {
    rectangle2 ScreenArea;
#if GAME_SLOW
    uint32 DebugTag;
#endif
    game_assets *Assets;
    camera_transform CameraTransform;
    v2 MonitorHalfDimInMeters;

    uint32 MissingResourceCount;
    bool32 RendersInBackground;

    uint32 GenerationID;
    game_render_commands *Commands;

    uint32 CurrentClipRectIndex;
    sprite_bound AggregateBound;
    sort_sprite_bound *FirstAggregate;
    bool32 IsAggregating;
};

struct entity_basis_p_result {
    v2 P;
    real32 SCale;
    bool32 Valid;
};

struct used_bitmap_dim {
    entity_basis_p_result Basis;
    v2 Size;
    v2 Align;
    v3 P;
};

inline object_transform DefaultUprightTransform(void) {
    object_transform Result = {};
    Result.Upright = true;
    Result.Scale = 1.0f;
    return Result;
};

inline object_transform SetFlatTransformSortBias(real32 ChunkZ) {
    object_transform Result = {};
    Result.Scale = 1.0f;
    Result.ChunkZ = (int32)ChunkZ;
    return Result;
};

inline object_transform DefaultFlatTransform(void) {
    object_transform Result = {};
    Result.Scale = 1.0f;
    return Result;
};

struct transient_clip_rect {
    transient_clip_rect(render_group *RenderGroupInit, uint32 NewClipRectIndex) {  //
        RenderGroup = RenderGroupInit;
        OldClipRect = RenderGroup->CurrentClipRectIndex;
        RenderGroup->CurrentClipRectIndex = NewClipRectIndex;
    }
    transient_clip_rect(render_group *RenderGroupInit) {
        RenderGroup = RenderGroupInit;
        OldClipRect = RenderGroup->CurrentClipRectIndex;
    }
    ~transient_clip_rect() {  //
        RenderGroup->CurrentClipRectIndex = OldClipRect;
    }
    render_group *RenderGroup;
    uint32 OldClipRect;
};
struct tile_sort_entry;
struct tile_render_work {
    game_render_commands *Commands;
    loaded_bitmap *RenderTargets;
    rectangle2i ClipRect;
    tile_sort_entry *SortSpace;
    game_render_prep *Prep;
};

// Renderer Api
void PushPiece(render_group *Group, object_transform *ObjectTransform, loaded_bitmap *Bitmap,
               v3 Offset, v2 Align, v2 Dim, v4 Color);
void PushRectOutline(render_group *Group, object_transform *ObjectTransform, v3 Offset, v2 Dim,
                     v4 Color, real32 Thickness);
void Clear(render_group *Group, v4 Color);
void *PushRenderElement_(render_group *Group, uint32 Size, render_group_entry_type Type,
                         sprite_bound SortKey, rectangle2 ScreenArea);

#define PushRenderElement(Group, Type, SoftKey, ScreenArea)                               \
    (Type *)PushRenderElement_(Group, sizeof(Type), RenderGroupEntryType_##Type, SoftKey, \
                               ScreenArea)

// 渲染一个矩形区域
void DrawRectangleQuickly(loaded_bitmap *Buffer, v2 Origin, v2 XAxis, v2 YAxis, v4 Color,
                          loaded_bitmap *Texture,  //
                          real32 PixelsToMeters, rectangle2i ClipRect);
used_bitmap_dim GetUsedBitmapDim(render_group *Group, object_transform *ObjectTransform,
                                 loaded_bitmap *Bitmap, real32 Height, v3 Offset);

void Perspective(render_group *RenderGroup, real32 MetersToPixels, real32 FocalLength,
                 real32 DistanceAboveTarget);
void PushBitmap(render_group *Group, object_transform *ObjectTransform, bitmap_id ID, real32 Height,
                v3 Offset, v4 Color = v4{1, 1, 1, 1}, real32 CAlign = 1.0f, v2 XAxis = {1, 0},
                v2 YAxis = {0, 1});
void PushBitmap(render_group *Group, object_transform *ObjectTransform, loaded_bitmap *Bitmap,
                real32 Height, v3 Offset, v4 Color = v4{1, 1, 1, 1}, real32 CAlign = 1.0f);
void PushBitmap(render_group *Group, object_transform *ObjectTransform, loaded_bitmap *Bitmap,
                real32 Height, v3 Offset, v4 Color, real32 CAlign, v2 XAxis = v2{1, 0},
                v2 YAxis = {0, 1});

loaded_font *PushFont(render_group *Group, font_id ID);
void Orthographic(render_group *RenderGroup, int32 PixelWidth, int32 PixelHeight,
                  real32 MetersToPixels, real32 DistanceAboveTarget = 1.0f,
                  real32 FocalLength = 0.6f);
void PushRectOutline(render_group *Group, object_transform *ObjectTransform, v3 Offset, v2 Dim,
                     v4 Color = {1.0f, 1.0f, 1.0f, 1.0f}, real32 Thickness = 0.1f);
bool32 AllResourcePresent(render_group *Group);
v3 Unproject(render_group *RenderGroup, object_transform *ObjectTransform, v2 PixelsXY);
used_bitmap_dim GetUsedBitmapDim(render_group *Group, object_transform *ObjectTransform,
                                 loaded_bitmap *Bitmap, real32 Height, v3 Offset, real32 CAlign,
                                 v2 XAxis = {1, 0}, v2 YAxis = v2{0, 1});
void PushRect(render_group *Group, object_transform *ObjectTransform,
              v3 Offset,  //
              v2 Dim, v4 Color = {1.0f, 1.0f, 1.0f, 1.0f});
void PushRect(render_group *Group, object_transform *ObjectTransform, rectangle2 Rectangle,
              real32 Z, v4 Color);
void RenderGroupToOutput(render_group *RenderGroup, loaded_bitmap *OutputTarget,
                         rectangle2i ClipRect);
void RenderGroupToOutput(render_group *RenderGroup, loaded_bitmap *OutputTarget,
                         memory_arena *TempArena);
rectangle2 GetCameraRectangleAtTarget(render_group *RenderGroup);
render_group BeginRenderGroup(game_assets *Assets, game_render_commands *Commands,
                              uint32 GenerationID, bool32 RendersInBackground, int32 PixelWidth,
                              int32 PixelHeight);
void ClearRenderValue(render_group *RenderGroup);
void RenderToOutput(platform_work_queue *RenderQueue, render_group *RenderGroup,
                    loaded_bitmap *OutputTarget, memory_arena *TempArena);
void PushRectOutline(render_group *Group, object_transform *ObjectTransform, rectangle2 Rectangle,
                     real32 Z, v4 Color, real32 Thickness);
uint32 PushClipRect(render_group *Group, uint32 X, uint32 Y, uint32 W, uint32 H,
                    uint32 RenderTargetIndex);
uint32 PushClipRect(render_group *Group, object_transform *ObjectTransform, v3 Offset, v2 Dim,
                    uint32 RenderTargetIndex);
uint32 PushClipRect(render_group *Group, object_transform *ObjectTransform, rectangle2 Rectangle,
                    real32 Z, uint32 RenderTargetIndex);
v4 StoreColor(object_transform *Transform, v4 Source);
void BeginAggregateSortKey(render_group *RenderGroup);
void EndAggregateSortKey(render_group *RenderGroup);
uint16 ReserveSortKey(render_group *RenderGroup);
void PushSortBarrier(render_group *RenderGroup, bool32 TurnOffSorting);
inline v4 Unpack4x8(uint32 Packed) {
    v4 Result = {// 获取源像素的红色通道值
                 (real32)((Packed >> 16) & 0xFF),
                 // 获取源像素的绿色通道值
                 (real32)((Packed >> 8) & 0xFF),
                 // 获取源像素的蓝色通道值
                 (real32)((Packed >> 0) & 0xFF),
                 // 获取源像素的Alpha通道值（范围0-255）
                 ((real32)((Packed >> 24) & 0xFF))};
    return Result;
}
inline uint32 Pack4x8(v4 Unpacked) {
    uint32 Result = ((RoundReal32ToUInt32(Unpacked.a) << 24) |  //
                     (RoundReal32ToUInt32(Unpacked.r) << 16) |  //
                     (RoundReal32ToUInt32(Unpacked.g) << 8) |   //
                     (RoundReal32ToUInt32(Unpacked.b) << 0));
    return Result;
}
void PushBlendRenderTarget(render_group *Group, real32 Alpha, uint32 SourceRenderTargetIndex);
#endif